﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using ProgNetComponents.Utils.EventHandlers;
using ProgNetComponents.Validation;
using ProgNetComponents.Validation.Rules;
using ProgNetComponents.Classes;
using System.Threading.Tasks;

namespace ProgNetComponentsDx.Validation
{
    public class ValidationProvider : Base.Components.BaseExtenderProvider<ValidationSettings>
    {
        public event DataRowEventHandler ValidationPassed;
        public event DataRowEventHandler ValidationFailed;

        public bool StopOnFirstError
        {
            get;
            set;
        }

        protected virtual void OnValidationPassed(ValidationRule rule, DataRow row)
        {
            if (ValidationPassed != null)
                ValidationPassed(rule, new DataRowEventArgs(row));
        }
        protected virtual void OnValidationFailed(ValidationRule rule, DataRow row)
        {
            if (ValidationFailed != null)
                ValidationFailed(rule, new DataRowEventArgs(row));
        }

        public virtual bool ValidateAll()
        {
            bool result = true;
            foreach (var settings in AllObjects.Values)
            {
                if (ValidateSettings(settings) == false)
                {
                    result = false;
                    if (StopOnFirstError)
                        return result;
                }
            }
            return result;
        }
        private class ParallelValidationSettings
        {
            public ObjectHolder<bool> Result
            {
                get;
                set;
            }
            public ValidationSettings Settings
            {
                get;
                set;
            }
        }
        private bool ValidateAllParallel()
        {
            ObjectHolder<bool> holder = new ObjectHolder<bool>(true);
            List<ParallelValidationSettings> list = new List<ParallelValidationSettings>();
            foreach (var s in AllObjects.Values)
            {
                if (s.Validate)
                    list.Add(new ParallelValidationSettings { Result = holder, Settings = s });
            }
            if (list.Count > 0)
            {
                Parallel.ForEach(list, (settings) =>
                {
                    if (!StopOnFirstError || settings.Result.Value)
                    {
                        if (!ValidateSettings(settings.Settings))
                        {
                            settings.Result.Value = false;
                        }
                    }
                });
            }
            return holder.Value;
        }
        private bool ValidateSettings(ValidationSettings settings)
        {
            bool result = true;
            if (settings.Validate)
            {
                settings.Rules.ValidationFailed += new DataRowEventHandler(Rules_ValidationFailed);
                settings.Rules.ValidationPassed += new DataRowEventHandler(Rules_ValidationPassed);
                try { result = settings.Rules.ValidateAll(StopOnFirstError); }
                finally
                {
                    settings.Rules.ValidationFailed -= new DataRowEventHandler(Rules_ValidationFailed);
                    settings.Rules.ValidationPassed -= new DataRowEventHandler(Rules_ValidationPassed);
                }
            }
            return result;
        }
        private void Rules_ValidationPassed(object sender, DataRowEventArgs e)
        {
            OnValidationPassed(sender as ValidationRule, e.Row);
        }

        private void Rules_ValidationFailed(object sender, DataRowEventArgs e)
        {
            OnValidationFailed(sender as ValidationRule, e.Row);
        }

        protected override void ProcessObject(object target, ValidationSettings settings)
        {
            
        }

        protected override ValidationSettings CreateSettings(object target)
        {
            return new ValidationSettings(target, this);
        }

        public override bool CanExtend(object extendee)
        {
            if (extendee is DataTable)
                return true;
            if (extendee is DataSet)
                return true;
            return false;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                foreach (var settings in AllObjects.Values)
                    settings.Dispose();
                AllObjects.Clear();
            }
            base.Dispose(disposing);
        }
    }
}
